﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FIXForge.NET.FIX;
using System.Threading;
using TAS;
namespace OMS
{
    public class OMSEngine 
    {
        public TradingManager tradingManager = null;
        public ManualResetEvent InterruptEvent { get; set; }

        Dictionary<string, SecurityEntity> securityEntityMap;

        public List<Order> orderQueue { get; set; }

        public void Initialize(Dictionary<string, SecurityEntity> securityEntityMap)
        {
            CreateTradingManager();
            this.securityEntityMap = securityEntityMap;
        }
        
        public void Initialize()
        {
            CreateTradingManager();
        }

        public void Connect()
        {
            try
            {
                tradingManager.Connect();
            }
            catch (Exception ex)
            {
                 return;
            }
        }

        public Order Buy(double tradeID, string securityDesc, double quantity, Order.OrderType ordertype)
        {
            try
            {
                Order order;

                Order.OrderType orderType = ordertype;
                Order.OrderSide orderSide = Order.OrderSide.Buy;

                string ClientOrderID = tradingManager.GetNextClientOrderID();


                order = new Order(ClientOrderID, orderType, orderSide, securityDesc, tradeID);
                
                order.Currency = "USD";
                order.Text = "";
                
                order.Quantity = quantity;
                order.SecurityID = securityEntityMap[securityDesc].ID;
                
                // order.InForce = tif;

                if (Order.OrderType.Market != order.Type && Order.OrderType.ForeignExchangeMarketOrder != order.Type)
                {
                    // order.Price = price;
                }
               // tradingManager.SendNewOrder(order); // never send from here

                return order;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public Order Sell(double tradeID, double quantity, string securityDesc,  Order.OrderType ordertype)
        {
            try
            {
                Order order;

                Order.OrderType orderType = ordertype;
                Order.OrderSide orderSide = Order.OrderSide.Sell;

                string ClientOrderID = tradingManager.GetNextClientOrderID();


                order = new Order(ClientOrderID, orderType, orderSide, securityDesc, tradeID);

                order.Currency = "USD";
                order.Text = "";
                
                order.Quantity = quantity;
                order.SecurityID = securityEntityMap[securityDesc].ID;
           //     order.InForce = tif;

                if (Order.OrderType.Market != order.Type && Order.OrderType.ForeignExchangeMarketOrder != order.Type)
                {
                   // order.Price = price;
                }
                // tradingManager.SendNewOrder(order); // never send from here

                return order;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public void Disconnect()
        {
            try
            {
                tradingManager.Disconnect();
            }
            catch (Exception ex)
            {
                return;
            }
        }

        void CreateTradingManager()
        {
            if (null != tradingManager)
            {
                tradingManager.OrderStateChanged -= new EventHandler<TradingManager.OrderStateChangedArgs>(OnOrderStateChanged);

                tradingManager.Session.InboundApplicationMsgEvent -= new Session.InboundApplicationMsgEventHandler(OnInboundApplicationMsgEvent);
                tradingManager.Session.InboundSessionMsgEvent -= new Session.InboundSessionMsgEventHandler(OnInboundSessionMsgEvent);
                tradingManager.Session.OutboundApplicationMsgEvent -= new Session.OutboundApplicationMsgEventHandler(OnOutboundApplicationMsgEvent);
                tradingManager.Session.OutboundSessionMsgEvent -= new Session.OutboundSessionMsgEventHandler(OnOutboundSessionMsgEvent);
                tradingManager.Session.MessageResending -= new Session.MessageResendingEventHandler(OnMessageResending);
                tradingManager.Session.StateChangeEvent -= new Session.StateChangeEventHandler(OnStateChangeEvent);
                tradingManager.Session.WarningEvent -= new Session.WarningEventHandler(OnWarningEvent);
                tradingManager.Session.ErrorEvent -= new Session.ErrorEventHandler(OnErrorEvent);

                tradingManager.Session.Dispose();
            }

            SessionConfiguration settings = new SessionConfiguration();
            settings.Account = "TestAccount";
            settings.ClientID = "";
            settings.HeartbeatInterval = 30;
            settings.Host = "localhost";
            settings.KeepSequenceNumbersAfterLogout = true;
            settings.Password = "password";
            settings.Port = 4500;
            settings.SenderCompID = "Client";
            settings.SetResetSeqNumFlag = false;
            settings.TargetCompID = "TradingGateway";
            settings.Username = "userName";
            settings.UseSslEncryption = false;
            settings.Version = ProtocolVersion.FIX42;

            tradingManager = new TradingManager(settings);

            tradingManager.OrderStateChanged += new EventHandler<TradingManager.OrderStateChangedArgs>(OnOrderStateChanged);
            tradingManager.Session.InboundApplicationMsgEvent += new Session.InboundApplicationMsgEventHandler(OnInboundApplicationMsgEvent);
            tradingManager.Session.InboundSessionMsgEvent += new Session.InboundSessionMsgEventHandler(OnInboundSessionMsgEvent);
            tradingManager.Session.OutboundApplicationMsgEvent += new Session.OutboundApplicationMsgEventHandler(OnOutboundApplicationMsgEvent);
            tradingManager.Session.OutboundSessionMsgEvent += new Session.OutboundSessionMsgEventHandler(OnOutboundSessionMsgEvent);
            tradingManager.Session.MessageResending += new Session.MessageResendingEventHandler(OnMessageResending);
            tradingManager.Session.StateChangeEvent += new Session.StateChangeEventHandler(OnStateChangeEvent);
            tradingManager.Session.WarningEvent += new Session.WarningEventHandler(OnWarningEvent);
            tradingManager.Session.ErrorEvent += new Session.ErrorEventHandler(OnErrorEvent);

            tradingManager.OnOrderTimerExpiredHandler += new TradingManager.OrderTimerExpiredHandler(OnOrderTimerExpiredHandler);
        }

        void OnOrderTimerExpiredHandler(Order order)
        {
            order.Status = Order.OrderStatus.Expired; // to be changed. cannot be tampered with.

            lock (orderQueue)
            {
                orderQueue.Add(order);
            }

            InterruptEvent.Set();
        }

        void OnOrderStateChanged(object sender, TradingManager.OrderStateChangedArgs e)
        {
            lock (orderQueue)
            {
                // revisit
                //orderQueue.RemoveAll(order => order.SecurityID == e.Order.SecurityID && order.Status == Order.OrderStatus.Expired);
                //orderQueue.Add(e.Order);
            }

            InterruptEvent.Set();
        }

        void OnErrorEvent(object sender, Session.ErrorEventArgs args)
        {
        }

        void OnWarningEvent(object sender, Session.WarningEventArgs args)
        {
        }

        void OnStateChangeEvent(object sender, Session.StateChangeEventArgs args)
        {
        }

        void OnMessageResending(object sender, Session.MessageResendingEventArgs e)
        {
        }

        void OnOutboundSessionMsgEvent(object sender, Session.OutboundSessionMsgEventArgs args)
        {
        }

        void OnOutboundApplicationMsgEvent(object sender, Session.OutboundApplicationMsgEventArgs args)
        {
        }

        void OnInboundSessionMsgEvent(object sender, Session.InboundSessionMsgEventArgs args)
        {
        }

        void OnInboundApplicationMsgEvent(object sender, Session.InboundApplicationMsgEventArgs args)
        {
        }


    }
}
